/*
DATE: 2021/12/07
AUTHOR: chenyihui
Desc:  钉钉告警功能封装
Ref : "https://developers.dingtalk.com/document/robots/custom-robot-access/title-72m-8ag-pqw" 官方文档

*/
package dingtalk

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	jsoniter "github.com/json-iterator/go"
	"github.com/pkg/errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

// 钉钉机器人消息发送url
const dingTalkURL = "https://oapi.dingtalk.com/robot/send?"

var dingTalk dingTalkClient

type dingTalkClient struct {
	token  string
	secret string

	httpCli *http.Client
}

// 推送消息
func (cli *dingTalkClient) push(msg interface{}) error {
	// step 1 marshal 数据
	msgBytes, err := jsoniter.Marshal(msg)
	if err != nil {
		return err
	}
	if len(msgBytes) == 0 {
		return errors.New("msg is null")
	}

	// step 2 处理url拼接
	value := make(url.Values, 0)
	value.Set("access_token", cli.token)
	if cli.secret != "" {
		t := time.Now().UnixNano() / 1e6
		value.Set("timestamp", fmt.Sprintf("%d", t))
		value.Set("sign", cli.sign(t, cli.secret))
	}
	uri := dingTalkURL + value.Encode()

	//step 3  handle header
	req, err := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(msgBytes))
	if err != nil {
		return err
	}
	req.Header.Set("Content-type", "application/json")

	// step 4 do http request
	resp, err := cli.httpCli.Do(req)
	if err != nil {
		return err
	}

	// step 5 handle resp
	if resp == nil {
		return errors.New("resp is nil")
	}
	if resp.StatusCode != http.StatusOK {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return fmt.Errorf("read body err %v", err)
		}
		return fmt.Errorf("send msg err: %s, token: %s, msg: %s", string(body), cli.token, msgBytes)
	}

	return nil
}

// 密钥签名
// 加密流程: sha256->base64-urlEncode
func (cli *dingTalkClient) sign(t int64, secret string) string {
	hash := fmt.Sprintf("%d\n%s", t, secret)
	hmac256 := hmac.New(sha256.New, []byte(secret))
	hmac256.Write([]byte(hash))
	data := hmac256.Sum(nil)
	return base64.StdEncoding.EncodeToString(data)
}
